﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using DynamicProxyCore;
using JetBrains.Annotations;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Test
{
	/// <summary>
	/// Summary description for UnitTest1
	/// </summary>
	[TestClass]
	public class UnitTest1
	{
		private class MyClass
		{
			MyClass _i;
			
			public string Name { get; set; }
			public MyClass Foo()
			{
				return _i ?? (_i = new MyClass{Name = "_sdfdsfsdfsfd"});
			}

			public IEnumerable<MyClass> GetChilds()
			{
				yield return new MyClass();
				yield return new MyClass();
			}
		}

		[TestMethod]
		public void TestPropertyChange()
		{
			var myClass = new MyClass();
			var propertyName = string.Empty;
			dynamic proxy = DynamicProxy.Create(myClass);

			((INotifyPropertyChanged) proxy).PropertyChanged += (s, a) => propertyName = a.PropertyName;

			proxy.Name = "aaaa";

			Assert.AreEqual("Name",propertyName);
		}

		[TestMethod]
		public void TestDynamicMethod()
		{
			var a = new MyClass{Name="123"};

			Assert.AreEqual("123",a.Name);
			Assert.AreEqual("_sdfdsfsdfsfd", a.Foo().Name);

			var x = 0;

			dynamic proxy = DynamicProxy.Create(a).AddProperty<bool>("IsSelected")
												  .AddProperty("X", _ => x, (_, value) => x = value)
												  .AddProperty("LastName","FFFF")
												  .AddMethod("Boo", new Func<DynamicProxy<MyClass>, int, string>((m, i) => ((MyClass)m).Name + i.ToString()));
														

			proxy.Name = "567";
			proxy.IsSelected = true;
			proxy.X = 42;
			var b = proxy.Foo();
			b.IsSelected = true;

			Assert.AreEqual("567",a.Name);
			Assert.AreEqual("5674",proxy.Boo(4));
			Assert.IsTrue(proxy.IsSelected);
			Assert.AreEqual(42, x);
			Assert.IsTrue(b.IsSelected);

			b.IsSelected = false;

			Assert.IsTrue(proxy.IsSelected);
			Assert.IsFalse(b.IsSelected);

			proxy.LastName = "890";
			var d = proxy.Foo();
			Assert.AreEqual("FFFF",d.LastName);

			var d2 = proxy.Foo();
			d2.LastName = "RRRRR";

			Assert.AreEqual("567",Foo(proxy));

			Assert.AreEqual(d.LastName,d2.LastName);

			var c = (MyClass)proxy;

			Assert.AreEqual("567",c.Name);

			foreach (var child in proxy.GetChilds())
			{
				child.IsSelected = true;
				Assert.IsTrue(child.IsSelected);
			} 
		}

		private string Foo(MyClass a)
		{
			return a.Name;
		}

		private class ANotDispose2 : ANotDispose
		{
			
		}

		private interface IMoon
		{
			ANotDispose GetA();
		}

		private class ANotDispose : IMoon
		{
			public string Name { get; set; }

			public ANotDispose GetA()
			{
				return new ANotDispose{Name="NameA"};
			}

			public ANotDispose GetB()
			{
				return new ANotDispose { Name = "NameB" };
			}

			public ANotDispose2 GetC()
			{
				return new ANotDispose2 { Name = "NameC" };
			}
		}

		private class DisposeImpl : IDisposable, IProxyInterfaceImplementaion<ANotDispose>
		{
			private readonly IList<string> _disposeList;
			private DynamicProxy<ANotDispose> _value;

			public DisposeImpl(IList<string> disposeList)
			{
				_disposeList = disposeList;
			}

			public void Dispose()
			{
				foreach (var proxy in _value.ChildProxies)
				{
					_disposeList.Add(proxy.Value.Name);
				} 
			}

			public void Activate(DynamicProxy<ANotDispose> value)
			{
				_value = value;
			}
		}

		

		[TestMethod]
		public void TestDisposeMethod()
		{
			var root = new ANotDispose {Name = "Root"};
			var disposeList = new List<string>();
			dynamic proxy = DynamicProxy.Create(root).AddInterface<IDisposable, DisposeImpl>(new DisposeImpl(disposeList));

			using (proxy)
			{
				proxy.GetA();
				proxy.GetB();
				proxy.GetC();
			}      
			

			CollectionAssert.Contains(disposeList,"Root");
			CollectionAssert.Contains(disposeList, "NameA");
			CollectionAssert.Contains(disposeList, "NameB");
			CollectionAssert.Contains(disposeList, "NameC");
		}

	}
}
